/**
 * 
 */
package vue.desktop;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.swing.BorderFactory;
import javax.swing.JPanel;

import model.cnf.CNF;
import model.session.PreprocessorExecutionBlock;
import vue.IIGSATPart;
import vue.session.IGBlock;
import vue.session.IGCNFUse;
import vue.session.IGExecutionBlock;
import vue.session.IGPreprocessorBlock;
import vue.session.IGSolverBlock;
import controller.ISessionManager;

/**
 * {@link IGDesktop} is a part of the application that allow you to see your progression in a
 * session with a graphical representation of the {@link CNF} and {@link PreprocessorExecutionBlock}
 * .
 * 
 * @author GRONOWSKI Stephane svan001@aol.com
 * 
 *         igsat 2010
 * 
 */
public class IGDesktop extends JPanel implements IIGSATPart, MouseMotionListener {

	private static final long							serialVersionUID	= 1L;
	public static final String							BORDER_TITLE		= "Desktop";
	public static final Color							BACKGROUND_COLOR	= Color.WHITE;


	public static final int								HEIGHT				= 700;
	public static final int								WIDTH				= 900;

	protected int										width				= WIDTH;
	protected int										height				= HEIGHT;
	protected Dimension									dim;

	private ISessionManager								manager;

	private Map<IGDeskCNFUse, Set<IGDeskPreprocessor>>	cnfUses				= new HashMap<IGDeskCNFUse, Set<IGDeskPreprocessor>>();
	private Map<IGDeskPreprocessor, Set<IGDeskCNFUse>>	preprocs			= new HashMap<IGDeskPreprocessor, Set<IGDeskCNFUse>>();

	private IGBlock										selected			= null;

	// private JPanel panel = new JPanel();

	public IGDesktop(ISessionManager manager) {
		setLayout(null);
		this.manager = manager;
		dim = new Dimension(width, height);


		// setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_AS_NEEDED);
		// setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_AS_NEEDED);
		setBorder(BorderFactory.createTitledBorder(BORDER_TITLE));

		setBackground(BACKGROUND_COLOR);
		setPreferredSize(dim);
		setSize(dim);


	}

	@Override
	public void addCNFUse(IGCNFUse cnfuse) {
		// TODO A tester

		// new data
		IGDeskCNFUse res = new IGDeskCNFUse(cnfuse, manager);
		res.addMouseMotionListener(this);

		// maj
		cnfUses.put(res, new HashSet<IGDeskPreprocessor>());

		add(res);

		// TODO coordonne
		// res.setLocation(100 * (preprocs.size() + cnfUses.size()), 100 * (preprocs.size() +
		// cnfUses.size()));
		res.setLocation(getWidth() / 2, getHeight() / 2);
		repaint();
		validate();
	}

	@Override
	public void addExecution(IGCNFUse cnfuse, IGExecutionBlock exec) {
		// do nothing
	}

	@Override
	public void addPreprocessor(IGCNFUse cnfuse, IGPreprocessorBlock preproc, IGCNFUse res) {
		// TODO Auto-generated method stub
		IGDeskCNFUse dep = null;
		IGDeskCNFUse arr = null;

		Set<IGDeskPreprocessor> pdep = null;
		Set<IGDeskPreprocessor> parr = null;

		for (IGDeskCNFUse cnf : cnfUses.keySet())
		{// seek the good igdeskcnfuse
			if (dep == null && cnf.getCnfuse() == cnfuse)
			{
				dep = cnf;
				pdep = cnfUses.get(dep);
				if (arr != null)
					break;
				else
					continue;
			}

			if (arr == null && cnf.getCnfuse() == res)
			{
				arr = cnf;
				parr = cnfUses.get(arr);
				if (dep != null)
					break;
				else
					continue;
			}
		}

		if (dep == null || arr == null)
			return; // cnf pas present

		// new data
		IGDeskPreprocessor prec = new IGDeskPreprocessor(preproc, manager);
		prec.addMouseMotionListener(this);
		Set<IGDeskCNFUse> setcnf = new HashSet<IGDeskCNFUse>();
		setcnf.add(dep);
		setcnf.add(arr);

		// maj
		pdep.add(prec);
		parr.add(prec);

		preprocs.put(prec, setcnf);

		// TODO coordonne

		add(prec);
		// prec.setLocation(100 * (preprocs.size() + cnfUses.size()), 100 * (preprocs.size() +
		// cnfUses.size()));
		prec.setLocation(getWidth() / 2, getHeight() / 2);
		repaint();
		//validate();
	}

	@Override
	public void addSolver(IGCNFUse cnfuse, IGSolverBlock solver) {
		// do nothing
	}

	@Override
	public void hasBeenModified(IGBlock block) {
		// TODO A tester

		for (IGDeskCNFUse cnf : cnfUses.keySet())
			if (cnf.getCnfuse() == block)
			{
				cnf.refresh();
				repaint();
				return;
			}

		for (IGDeskPreprocessor pre : preprocs.keySet())
			if (pre.getPreproc() == block)
			{
				pre.refresh();
				repaint();
				return;
			}

	}

	@Override
	public void hasBeenRemoved(IGBlock block) {
		// TODO A tester
		if (selected == block)
			selected = null;

		IGDeskCNFUse cnfuse = null;
		for (IGDeskCNFUse cnf : cnfUses.keySet())
			if (cnf.getCnfuse() == block)
			{
				cnfuse = cnf;
				break;
			}
		if (cnfuse != null)
		{
			// ig
			remove(cnfuse);

			// maj
			Set<IGDeskPreprocessor> setpre = cnfUses.remove(cnfuse);
			for (IGDeskPreprocessor pre : setpre)
				preprocs.get(pre).remove(cnfuse);

			repaint();
			return;
		}

		IGDeskPreprocessor preproc = null;
		for (IGDeskPreprocessor pre : preprocs.keySet())
			if (pre.getPreproc() == block)
			{
				preproc = pre;
				break;
			}
		if (preproc != null)
		{
			// ig
			remove(preproc);

			// maj
			Set<IGDeskCNFUse> setcnf = preprocs.remove(preproc);
			for (IGDeskCNFUse cnf : setcnf)
				cnfUses.get(cnf).remove(preproc);

			repaint();
			return;
		}

	}

	@Override
	public void hasBeenSelected(IGBlock block) {
		// TODO a tester
		if (selected == block || block == null)
			return;

		IGBlock oldSelected = selected;
		selected = null;
		boolean select = false;
		boolean deselect;

		if (oldSelected == null)
			deselect = true;
		else
			deselect = false;


		for (IGDeskCNFUse cnf : cnfUses.keySet())
		{// check cnf
			if (!deselect && cnf.getCnfuse() == oldSelected)
			{
				cnf.setSelected(false);

				if (select)
					return; // deja deselectionner et selectionner le nouveau
				else
					deselect = true;
				continue;
			}

			if (!select && cnf.getCnfuse() == block)
			{
				cnf.setSelected(true);
				selected = block;

				if (deselect)
					return; // deja deselectionner et selectionner le nouveau
				else
					select = true;
				continue;
			}
		}

		for (IGDeskPreprocessor pre : preprocs.keySet())
		{// check preproc
			if (!deselect && pre.getPreproc() == oldSelected)
			{
				pre.setSelected(false);

				if (select)
					return; // deja deselectionner et selectionner le nouveau
				else
					deselect = true;
				continue;
			}

			if (!select && pre.getPreproc() == block)
			{
				pre.setSelected(true);
				selected = block;

				if (deselect)
					return; // deja deselectionner et selectionner le nouveau
				else
					select = true;
				continue;
			}
		}
	}


	@Override
	public void mouseDragged(MouseEvent e) {
		// TODO Auto-generated method stub
		Component compo = e.getComponent();

		// new coor
		int x = compo.getX() + (e.getX() - compo.getWidth() / 2);
		int y = compo.getY() + (e.getY() - compo.getHeight() / 2);

		// check border
		if (x < 0)
			x = 0;
		else
			if (x > getSize().width - compo.getWidth())
				x = getSize().width - compo.getWidth();

		if (y < 0)
			y = 0;
		else
			if (y > getSize().height - compo.getHeight())
				y = getSize().height - compo.getHeight();

		// set location
		e.getComponent().setLocation(x, y);
		repaint();

	}

	@Override
	public void mouseMoved(MouseEvent e) {
		// do nothing
	}

	@Override
	protected void paintComponent(Graphics g) {
		// TODO Auto-generated method stub

		super.paintComponent(g);
		// g.setColor(BACKGROUND_COLOR);
		// g.fillRect(0, 0, g.getClipBounds().width, g.getClipBounds().height);
		// g.setColor(Color.black);
		for (IGDeskPreprocessor pre : preprocs.keySet())
		{
			int x = pre.getX() + pre.getSize().width / 2;
			int y = pre.getY() + pre.getSize().height / 2;

			for (IGDeskCNFUse cnf : preprocs.get(pre))
				g.drawLine(x, y, cnf.getX() + cnf.getSize().width / 2, cnf.getY() + cnf.getSize().height / 2);
		}


	}

	public void aze(Graphics g) {
		// TODO Auto-generated method stub
		// g.getClipRect().setSize(dim);
		// g.setColor(Color.white);
		// g.fillRect(0, 0, width, height);
		// g.setColor(Color.black);
		super.paint(g);


		for (IGDeskPreprocessor pre : preprocs.keySet())
		{
			int x = pre.getX() + pre.getSize().width / 2;
			int y = pre.getY() + pre.getSize().height / 2;

			for (IGDeskCNFUse cnf : preprocs.get(pre))
				g.drawLine(x, y, cnf.getX() + cnf.getSize().width / 2, cnf.getY() + cnf.getSize().height / 2);
		}

		// for(IGDeskCNFUse cnf : cnfUses.keySet())
		// cnf.repaint();


	}

}
